package com.young.ums.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 发布订阅中心,控制ums内部主题生产和消费,解耦服务之间的复杂关联
 * @author imrookie
 * @date 2018/10/14
 */
@Component
public class PublishSubscribeCenter implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(PublishSubscribeCenter.class);

    //主题与订阅者关联关系
    private Map<ETopic, List<ISubscriber>> topicSubscriber = new HashMap<ETopic, List<ISubscriber>>();

    /**
     * 订阅指定主题
     * @param topics 主题
     * @param subscriber 订阅者(观察者)
     */
    public void register(ETopic[] topics, ISubscriber subscriber){
        if (topics == null || topics.length == 0 || subscriber == null){
            logger.warn("[UMS发布订阅中心-注册订阅] 订阅失败:主题或订阅者无效.主题={},订阅者={}", topics, subscriber);
            return;
        }
        for(ETopic topic : topics){
            //查询主题对应的订阅者列表
            List<ISubscriber> list = topicSubscriber.get(topic);
            if (list != null){//存在列表,则追加进去
                if (list.contains(subscriber)){
                    logger.warn("[UMS发布订阅中心-注册订阅] 当前主题[{}]与订阅者[{}]已存在订阅关系.", topic, subscriber);
                }else{
                    list.add(subscriber);
                }
            }else{//不存在,则新建
                list = new ArrayList<ISubscriber>();
                list.add(subscriber);
                topicSubscriber.put(topic, list);
            }
        }
    }

    /**
     * 发布消息
     * @param topic 主题
     * @param message 消息对象
     */
    public void publish(ETopic topic, Object message){
        //查询指定主题的订阅列表
        List<ISubscriber> list = topicSubscriber.get(topic);
        if (list != null && list.size() > 0){
            logger.info("[UMS发布订阅中心-发布消息] 主题={},消息对象={},订阅者={}", topic, message, list);
            for (ISubscriber subscriber : list){
                subscriber.consume(topic, message);
            }
        }else{
            logger.warn("[UMS发布订阅中心-发布消息] 主题[{}]对应的订阅列表为空!", topic);
        }
    }

    //通过实现ApplicationContextAware来自动加载ums订阅者
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        //获取所有的订阅接口bean
        Map<String, ISubscriber> map = applicationContext.getBeansOfType(ISubscriber.class);
        if (map != null && !map.isEmpty()){
            for (Map.Entry<String, ISubscriber> entry : map.entrySet()){
                ISubscriber subscriber = entry.getValue();
                //获取订阅者订阅的主题数组并订阅
                this.register(subscriber.topics(), subscriber);
            }
        }
        logger.info("[UMS发布订阅中心] 初始化完成!");
    }
}
